package org.example;

import org.apache.zookeeper.*;
import org.apache.zookeeper.data.Stat;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CountDownLatch;

public class DistributedLock {

    private String connectString = "10.211.55.102:2181,10.211.55.103:2181,10.211.55.104:2181";
    private int sessionTimeout = 80000;
    private ZooKeeper zkClient;

    private CountDownLatch countDownLatch = new CountDownLatch(1);
    private String currentNode;

    public DistributedLock() throws InterruptedException, IOException, KeeperException {

        zkClient = new ZooKeeper(connectString, sessionTimeout, event -> {
            if (event.getState() == Watcher.Event.KeeperState.SyncConnected) {
                countDownLatch.countDown();
            }

            if ((event.getType() == Watcher.Event.EventType.NodeDeleted) && event.getPath().equals(waitPath) ){
                waitLatch.countDown();

            }
        });

        countDownLatch.await();

        Stat stat = zkClient.exists("/locks", false);
        if (stat == null) {
            zkClient.create("/locks", "locks".getBytes(StandardCharsets.UTF_8), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
        }
    }

    /**
     * 前一个节点
     */
    private String waitPath;

    private CountDownLatch waitLatch = new CountDownLatch(1);

    /**
     * 加锁
     */
    public void lock() {
        // 创建对应的临时带序号节点
        try {
            currentNode = zkClient.create("/locks/sql-", null, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
            System.out.println("创建节点的实际路径:    " + currentNode);
            List<String> children = zkClient.getChildren("/locks", false);
            if (children.size() == 1) {
                return ;
            } else {
                Collections.sort(children);

                String chillerNodeStr = currentNode.substring("/locks/".length());
                int i = children.indexOf(chillerNodeStr);
                if (i == -1) {
                    System.out.println("数据异常");
                } else if (i == 0) {
                    return;
                } else {
                    waitPath = "/locks/" + children.get(i - 1);
                    zkClient.getData(waitPath, true, null);

                    // 等待监听
                    waitLatch.await();
                    return;
                }

            }
        } catch (KeeperException | InterruptedException e) {
            throw new RuntimeException(e);
        }

        // 判断创建的节点是否是最小的序号节点，如果是获取到锁. 如果不是，监听他序号前一个节点
    }

    /**
     * 解锁
     */
    public void unlock() {
        try {
            zkClient.delete(currentNode, -1);
        } catch (InterruptedException | KeeperException e) {
            throw new RuntimeException(e);
        }
    }



}

